package cooperated

import (
	"bytes"
	"fmt"

	"gddgame.cc/galaxy/common/namespaces/cooperate"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/project/breeder/breeder/center"
	"gddgame.cc/galaxy/project/breeder/breeder/model"
	"gddgame.cc/galaxy/utils"
)

const (
	OnDestroyEvent = iota // 攻击销毁事件
	OnArriveEvent
	OnStartMoveEvent
)

func (logic *TypeMap) OnError(accountId int, err error) {
	logic.Center.OnNoticeError(logic, accountId, err)
}

func (logic *TypeMap) OnEvent(event byte, params []interface{}) {
	switch event {
	case OnDestroyEvent:
		logic.OnDestroy(params[0].(structure.Data), params[1].(cooperate.PropsInstance))
	case OnArriveEvent:
		logic.OnArrive(params[0].(cooperate.PropsInstance), utils.ToInt(params[1]), utils.ToBytes(params[2]), params[3].(*cooperate.MoveScheduleContent), utils.ToInt64(params[4]))
	case OnStartMoveEvent:
		logic.OnStartMove(params[0].(cooperate.PropsInstance), utils.ToBytes(params[1]), params[2].(*cooperate.MoveScheduleContent))
	}
}

func (logic *TypeMap) OnDestroy(from structure.Data, target cooperate.PropsInstance) {
	position := target.ToBytes(Position)
	ignore := target.ToBool(Ignore)
	identity := target.ToInt(Identity)
	// 已经被忽略
	if ignore {
		//fmt.Println("destroy ignore", target)
		return
	}
	key := target.ToString(Key)
	id := logic.Center.TargetIdMap[target.GetDataType()][key]
	level := target.ToInt(Level)
	abilityProp := ReceiveAbilityProp(target)
	itemId := 0
	fmt.Println("destroy", target.Data(), target, position, from)
	var operates []cooperate.UpdateOperateContent
	operates = append(operates, cooperate.UpdateOperateContent{
		Operate: cooperate.RemoveSchedule,
		Key:     "process",
	})
	if target.GetDataType() == BuildType {
		buildInfo := logic.Center.BuildMap[id]
		itemId = buildInfo.DestroyItem
		positionString := utils.ToString(position)
		_, ok := logic.regionIndexMap[positionString]
		//fmt.Println("destroy build", from, target, index, ok, position, sm.CurrentTime())

		updateData := cooperate.OperateContent{
			MapNoId:  logic.GetMapNoId(),
			Target:   target.Data(),
			Operates: []cooperate.OperateData{},
		}
		if ok {
			// 先获取from的信息
			fromInstance := logic.GetDetailCache(logic, from)
			identity = fromInstance.ToInt(Identity)
			// 占领：直接更新node的identity信息
			nodeOperate := &cooperate.UpdateOperateData{
				Data: *structure.NewBaseData(NodeType, position),
				Operates: []cooperate.UpdateOperateContent{{
					Operate: cooperate.ChangeData,
					Key:     Identity,
					Value:   identity,
				}},
			}
			updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, nodeOperate))
			// 占领：直接更新region的identity信息
			regionOperate := &cooperate.UpdateOperateData{
				Data: *structure.NewBaseData(RegionType, position),
				Operates: []cooperate.UpdateOperateContent{{
					Operate: cooperate.ChangeData,
					Key:     Identity,
					Value:   identity,
				}},
			}
			updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, regionOperate))
			// 占领：直接更新build的identity信息
			buildOperate := &cooperate.UpdateOperateData{
				Data: *target.Data(),
				Operates: []cooperate.UpdateOperateContent{{
					Operate: cooperate.ChangeData,
					Key:     Identity,
					Value:   identity,
				}},
			}
			updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, buildOperate))

		}

		buildUnitDepend := logic.DefaultBeDepend(BuildType, UnitDataType)
		units := target.ListDepend(buildUnitDepend)
		if units != nil && len(units) > 0 {
			for _, v := range units {
				// 取消托管，返回
				unit := logic.GetDetailCache(logic, structure.NewBaseData(UnitType, v))
				if _, ok := unit.GetProp2(AiFortress); ok {
					continue
				}
				updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, &cooperate.UpdateOperateData{
					Data: *unit.Data(),
					Operates: []cooperate.UpdateOperateContent{{
						Operate: cooperate.RemoveDepend,
						Key:     BuildDataType,
						Value:   nil,
					}, {
						Operate: cooperate.ChangePosition,
						Value:   nil,
					}, {
						Operate: cooperate.ChangeIgnore,
						Value:   true,
					}},
				}))
			}
		}
		fortress := target.Inherit(FortressDataType)
		// 建筑是要塞
		if fortress != nil && bytes.Equal(utils.ToBytes(fortress.GetId()), position) {
			fortressInstance := logic.GetDetailCache(logic, structure.NewBaseData(FortressType, position))
			fortress := fortressInstance.(*Fortress)

			for _, v := range fortress.Builds {
				build := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, utils.ToInt(v)))
				updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, &cooperate.UpdateOperateData{
					Data: *build.Data(),
					Operates: []cooperate.UpdateOperateContent{{
						Operate: cooperate.ChangeData,
						Key:     Identity,
						Value:   identity,
					}},
				}))
			}
			for _, v := range fortress.AiUnits {
				unit := logic.GetDetailCache(logic, structure.NewBaseData(UnitType, v))
				updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, &cooperate.UpdateOperateData{
					Data: *unit.Data(),
					Operates: []cooperate.UpdateOperateContent{{
						Operate: cooperate.ChangeData,
						Key:     Identity,
						Value:   identity,
					}},
				}))
			}
			for _, v := range fortress.Units {
				// 取消托管，返回
				unit := logic.GetDetailCache(logic, structure.NewBaseData(UnitType, v))
				// 取消ai关系，自动被攻击，按自动销毁处理
				updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, &cooperate.UpdateOperateData{
					Data: *unit.Data(),
					Operates: []cooperate.UpdateOperateContent{{
						Operate: cooperate.RemoveDepend,
						Key:     FortressDataType,
						Value:   nil,
					}},
				}))
			}
			for _, v := range fortress.AiBuilds {
				build := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, v.Position))
				updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, &cooperate.UpdateOperateData{
					Data: *build.Data(),
					Operates: []cooperate.UpdateOperateContent{{
						Operate: cooperate.ChangeData,
						Key:     Identity,
						Value:   identity,
					}},
				}))

			}
			for _, v := range fortress.Builds {
				build := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, v.Position))
				updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.BatchUpdateOperate, &cooperate.UpdateOperateData{
					Data: *build.Data(),
					Operates: []cooperate.UpdateOperateContent{{
						Operate: cooperate.ChangeData,
						Key:     Identity,
						Value:   identity,
					}, {
						Operate: cooperate.RemoveDepend,
						Key:     AccountDataType,
						Value:   nil,
					}},
				}))
			}
		}
		if len(updateData.Operates) > 0 {
			logic.PushOperate(updateData, 0)
		}
	} else if target.GetDataType() == UnitType {
		unit := logic.Center.UnitMap[id]
		itemId = unit.DestroyItem
		if target.ToInt(AccountDataType) > 0 {
			// 部队死亡，回到lastRegion
			lastRegion := target.ToBytes(LastRegion)
			if lastRegion != nil && len(lastRegion) > 0 {
				//p := utils.ToString(lastRegion)
				//buildId, _ := logic.buildIdMap.Load(p)
				build := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, lastRegion))
				if build == nil || build.ToInt(Identity) != identity {
					operates = append(operates, cooperate.UpdateOperateContent{
						Operate: cooperate.ChangePosition,
						Value:   nil,
					}, cooperate.UpdateOperateContent{
						Operate: cooperate.ChangeIgnore,
						Value:   true,
					}, cooperate.UpdateOperateContent{
						Operate: cooperate.ChangeData,
						Key:     UnitStatus,
						Value: &cooperate.Sustain{
							Type:     model.UnitInFree,
							Params:   nil,
							Start:    logic.CurrentTime(),
							Time:     0,
							CanBreak: true,
						},
					})
					logic.Center.OnUnitDown(logic, target.ToInt(AccountDataType), utils.ToString(target.GetId()))
				} else {
					operates = append(operates, cooperate.UpdateOperateContent{
						Operate: cooperate.ChangePosition,
						Value:   lastRegion,
					}, cooperate.UpdateOperateContent{
						Operate: cooperate.AddDepend,
						Index:   int(BuildType),
						Value:   build.GetId(),
						Key:     BuildDataType,
					}, cooperate.UpdateOperateContent{
						Operate: cooperate.ChangeIgnore,
						Value:   true,
					})
				}
			} else {
				operates = append(operates, cooperate.UpdateOperateContent{
					Operate: cooperate.ChangePosition,
					Value:   nil,
				}, cooperate.UpdateOperateContent{
					Operate: cooperate.ChangeIgnore,
					Value:   true,
				}, cooperate.UpdateOperateContent{
					Operate: cooperate.ChangeData,
					Key:     UnitStatus,
					Value: &cooperate.Sustain{
						Type:     model.UnitInFree,
						Params:   nil,
						Start:    logic.CurrentTime(),
						Time:     0,
						CanBreak: true,
					},
				})
				logic.Center.OnUnitDown(logic, target.ToInt(AccountDataType), utils.ToString(target.GetId()))
			}
			if target.ToBool(MoveStatus) {
				//fmt.Println("destroy unit move", target.Data())
				operates = append(operates, cooperate.UpdateOperateContent{
					Operate: cooperate.ChangeData,
					Key:     MoveStatus,
					Value:   false,
				})
			}
		}
		logic.MoveSeat(target.GetItem(), position, nil, logic.CurrentTime(), 0, abilityProp.View, nil)
	}
	if operates != nil && len(operates) > 0 {
		logic.operateOne(logic.GetMapNoId(), target.Data(), operates, 500)
	}
	// 取消监听驻守等逻辑
	listenInfo := target.ToBytesSlice(Listen)
	if len(listenInfo) > 0 {
		// 需要取消listen
		logic.OnListen(target, identity, &ListenLogic{
			Nodes:  listenInfo,
			Switch: false,
		}, 0)
	}

	// buff死亡后清除逻辑
	if abilityProp != nil {
		operates := []cooperate.UpdateOperateContent{}
		for index, buffInfo := range abilityProp.BuffInfoSlice {
			buff := logic.Center.BuffMap[buffInfo.BuffId]
			if buff.IsDeathClear {
				operates = append(operates, cooperate.UpdateOperateContent{
					Operate: cooperate.RemoveTimeSorted,
					Key:     string(BuffAbilityExtend),
					Value:   abilityProp.BuffAbilityExtend[index],
				})
			}
		}
		if len(operates) > 0 {
			logic.operateOne(logic.GetMapNoId(), structure.NewBaseDataFrom(target), operates, 500)
		}
	}

	// 发送销毁
	owner := logic.GetAbilityInstance(logic, target)
	effect := owner.Generate(logic, target, logic)

	destroy := &DestroyTask{
		DataType: target.GetDataType(),
		Id:       target.GetId(),
		Identity: identity,
		Key:      key,
		Position: position,
		Ability: &Ability{
			Level:         level,
			DirectAbility: effect.GetIds(model.DirectAbilityDefine),
			BuffAbility:   effect.GetIds(model.BuffAbilityDefine),
			AttrAbility:   effect.GetSlice(model.AttrAbilityDefine),
		},
		Params: []interface{}{"account", target.ToInt(AccountDataType)},
	}
	builder := logic.TaskBuilder()
	if from != nil {
		builder.From(structure.NewBaseDataFrom(from))
	}
	builder.BindMapNoId(logic.GetMapNoId()).One(DestroyTaskEvent, destroy).Task(0, nil)

	fromInstance := logic.GetDetailCache(logic, from)
	logic.Center.TriggerStat(center.BattleDestroyTriggerEvent, logic, fromInstance, target, 0)
	if itemId > 0 {
		// 添加掉落
		logic.createItem(0, BaseIdentityType, itemId, position, "")
	}

	// 战斗奖励
	battleProp := ReceiveBattleProp(target)
	if battleProp != nil {
		totalXp := int32(100)
		ma := map[string]*struct {
			Instance cooperate.PropsInstance
			Score    int32
		}{}
		//if battleProp.InjurySlice == nil {
		//	fmt.Println("battle prop", battleProp)
		//} else if battleProp.InjurySlice.Items == nil {
		//	fmt.Println("battle prop injury", battleProp.InjurySlice)
		//}
		for _, item := range battleProp.InjurySlice.Items {
			name := item.ToString()
			if v, ok := ma[name]; ok {
				v.Score = v.Score + item.Score
			} else {
				ma[name] = &struct {
					Instance cooperate.PropsInstance
					Score    int32
				}{
					Instance: logic.GetDetailCache(logic, &item.BaseData),
					Score:    item.Score,
				}
			}
		}
		for _, value := range ma {
			//fmt.Println("gain xp", target, value.Instance, value.Score, battleProp.InjurySlice.Total, value.Score*totalXp/battleProp.InjurySlice.Total)
			logic.Center.TriggerStat(center.GainXPTriggerEvent, logic, target, value.Instance, value.Score*totalXp/battleProp.InjurySlice.Total)
		}

	}

}

func (logic *TypeMap) OnStartMove(instance cooperate.PropsInstance, position []byte, content *cooperate.MoveScheduleContent) {
	selfIdentity := instance.ToInt(Identity)
	listenInfo := instance.ToBytesSlice(Listen)
	if len(listenInfo) > 0 {
		// 开始移动，如果部队驻守，则取消驻守
		logic.OnListen(instance, selfIdentity, &ListenLogic{
			Nodes:  listenInfo,
			Switch: false,
		}, 0)
	}
	operates := []cooperate.UpdateOperateContent{}
	operateData := &cooperate.UpdateOperateData{
		Data: *instance.Data(),
	}
	//fmt.Println("move", instance.Inherits())
	buildIn := instance.Inherit(BuildDataType)
	fmt.Println("start", logic.GetMapNoId(), instance.Data(), instance.ToInt(Identity), instance.GetItem(), buildIn, position, content.Plan, content.Positions)
	if buildIn != nil {
		buildInstance := logic.GetDetailCache(logic, buildIn)
		if buildInstance == nil {
			return
		}
		positions := buildInstance.ToBytesSlice(Positions)
		// 如果在建筑内，则瞬移到建筑外，ignore=false
		// 并发送消息
		// 修改moveContent的移动路径，修改起点
		i := 0
		for index, p := range content.Positions {
			flag := false
			for _, ps := range positions {
				if bytes.Equal(p, ps) {
					flag = true
					break
				}
			}
			if flag {
				continue
			}
			i = index
			break
		}
		//fmt.Println("start move", buildId, positions, instance.BaseData(), content.Positions, content.Plan, i, content.Positions[i], content.TargetPositions)
		startPosition := content.Positions[i]
		content.Plan[0] = startPosition
		content.Positions = content.Positions[i:]
		// 如果position过短，补完nextposition，交由移动内部实现重新寻路
		if len(content.Positions) <= 1 {
			content.Positions = append(content.Positions, startPosition)
		}
		// 离开建筑
		//buildData := structure.NewBaseData(BuildType, buildId)
		operates = append(operates, cooperate.UpdateOperateContent{
			Operate: cooperate.RemoveDepend,
			Index:   int(BuildType),
			Value:   buildInstance.GetId(),
			Key:     BuildDataType,
		}, cooperate.UpdateOperateContent{
			Operate: cooperate.ChangeIgnore,
			Value:   false,
		}, cooperate.UpdateOperateContent{
			Operate: cooperate.ChangePosition,
			Value:   startPosition,
		})
		extend := cooperate.NewModeExtend([]interface{}{startPosition}, logic.GetMapNoId(), nil, startPosition)
		operateData.Operates = operates
		extend.UpdateOperate = operateData
		logic.Mode(logic, nil, instance, *logic.Event.OnTeleportOut, 0, extend)
		// 直接设定占位，可能立即被下一个替换，但不影响，至少该节点可被攻击
		logic.setBlock(instance, nil, startPosition, nil, logic.CurrentTime(), 0, selfIdentity, NormalTargetVisible)
	} else if len(operates) > 0 {
		operateData.Operates = operates
		updateData := cooperate.OperateContent{
			MapNoId: logic.GetMapNoId(),
			Target:  &operateData.Data,
			Operates: []cooperate.OperateData{
				cooperate.NewOperateData(cooperate.BatchUpdateOperate, operateData),
			},
		}
		logic.PushOperate(updateData, 0)
	}
}
func (logic *TypeMap) OnArrive(instance cooperate.PropsInstance, selfIdentity int, position []byte, content *cooperate.MoveScheduleContent, current int64) {
	targetPosition := content.Positions[len(content.Positions)-1]
	var defendDistance int
	abilityProp := ReceiveAbilityProp(instance)
	moveProp := ReceiveMoveProp(instance)
	if moveProp.Visible != NormalTargetVisible {
		// 隐身状态，不进入驻守状态
		defendDistance = 0
	} else {
		defendDistance = abilityProp.GetAttrWithId(logic.DefendDistance) // 驻守距离
	}
	fmt.Println("end", instance.Data(), instance.GetItem(), position, targetPosition)
	operates := []cooperate.UpdateOperateContent{}
	if targetPosition != nil && !bytes.Equal(targetPosition, position) {
		distance := logic.Distance(targetPosition, position)
		//targetString := utils.ToString(targetPosition)
		in := false
		//buildId := 0
		//if _, ok := logic.withCenterIndexMap[targetString]; ok {
		//	in = true
		//}
		buildInstance := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, targetPosition))
		if buildInstance != nil {
			// 相同势力，则可以进入
			build := buildInstance.(*Build)
			// 对于允许进入的建筑，判断是否在建筑旁边
			if build.GetAttrWithId(logic.CanTeleportIn) > 0 {
				l := len(build.Positions)
				if (distance-1)*distance/2*6+1 <= l {
					//fmt.Println("in miss", instance.BaseData(), position, targetPosition, distance, build.Positions, (distance-1)*distance/2*6, content.Positions, content.Plan)
					if p, _ := logic.JudgeIdentity(selfIdentity, buildInstance.ToInt(Identity)); p {
						in = true
					}
				}
			}
		}
		//fmt.Println("in", instance.Data(), in, position, targetPosition)
		if in {
			// 目标点是建筑，当前点是建筑边，瞬移进建筑
			//
			// 进入建筑
			//buildData := structure.NewBaseData(BuildType, buildId)
			operates = append(operates, cooperate.UpdateOperateContent{
				Operate: cooperate.AddDepend,
				Index:   int(BuildType),
				Value:   buildInstance.GetId(),
				Key:     BuildDataType,
			}, cooperate.UpdateOperateContent{
				Operate: cooperate.ChangeIgnore,
				Value:   true,
			}, cooperate.UpdateOperateContent{
				Operate: cooperate.ChangePosition,
				Value:   targetPosition,
			})
			extend := cooperate.NewModeExtend([]interface{}{position}, logic.GetMapNoId(), nil, position)
			logic.Mode(logic, nil, instance, *logic.Event.OnTeleportIn, 0, extend)
			// 进入建筑，取消驻守
			defendDistance = 0

			// 进入后，更新300秒，5分钟
			instance.ClearTimeSorted(logic, BuffAbilityExtend, abilityProp.BuffInfoSlice, abilityProp.lastClearBuffSecond, 300)

			// 下一格是建筑范围，则取消占位即可
			logic.MoveSeat(instance.GetItem(), position, nil, current, 0, abilityProp.View, nil)
		}
	}
	if len(operates) > 0 {
		operateData := &cooperate.UpdateOperateData{
			Data:     *instance.Data(),
			Operates: operates,
		}
		updateData := cooperate.OperateContent{
			MapNoId: logic.GetMapNoId(),
			Target:  &operateData.Data,
			Operates: []cooperate.OperateData{
				cooperate.NewOperateData(cooperate.BatchUpdateOperate, operateData),
			},
		}
		logic.PushOperate(updateData, 100)
	}
	// 先驻守，然后执行到达事件
	// 如果到达事件是返回，内部从移动开始中取消驻守
	if defendDistance > 0 {
		aiMode := AiModeDefine(instance.ToByte(AiMode))
		if aiMode == DefendAiMode {
			findEvent := instance.GetEvent(ListenSystemEvent)
			if findEvent != nil {
				positions := logic.RangeDistance(position, defendDistance-1)
				// 如果部队不在建筑上，则驻守周围
				logic.OnListen(instance, selfIdentity, &ListenLogic{
					Nodes:  positions,
					Switch: true,
				}, current)
			}
		}
	}
	//fmt.Println("defend", defendDistance)
	e := instance.GetEvent(ArriveInlineEvent)
	if e != nil {
		extend := cooperate.NewModeExtend([]interface{}{}, logic.GetMapNoId(), nil, position)
		logic.Mode(logic, instance, instance, *e, current+100, extend)
		logic.ClearEvent(logic.GetMapNoId(), instance, ArriveInlineEvent)
	}
}
func (logic *TypeMap) OnFly(data structure.Data, currentPosition []byte, targetPosition []byte) {
	currentBuild := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, currentPosition))

	targetBuild := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, currentPosition))
	//currentString := utils.ToString(currentPosition)
	//currentBuildId, _ := logic.buildIdMap.Load(currentString)
	//targetString := utils.ToString(targetPosition)
	//targetBuildId, _ := logic.buildIdMap.Load(targetString)
	operates := []cooperate.UpdateOperateContent{}
	operates = append(operates, cooperate.UpdateOperateContent{
		Operate: cooperate.RemoveDepend,
		Index:   int(BuildType),
		Value:   currentBuild.GetId(),
		Key:     BuildDataType,
	}, cooperate.UpdateOperateContent{
		Operate: cooperate.AddDepend,
		Index:   int(BuildType),
		Value:   targetBuild.GetId(),
		Key:     BuildDataType,
	}, cooperate.UpdateOperateContent{
		Operate: cooperate.ChangeIgnore,
		Value:   true,
	}, cooperate.UpdateOperateContent{
		Operate: cooperate.ChangePosition,
		Value:   targetPosition,
	})
	operateData := &cooperate.UpdateOperateData{
		Data:     *structure.NewBaseDataFrom(data),
		Operates: operates,
	}
	updateData := cooperate.OperateContent{
		MapNoId: logic.GetMapNoId(),
		Target:  &operateData.Data,
		Operates: []cooperate.OperateData{
			cooperate.NewOperateData(cooperate.BatchUpdateOperate, operateData),
		},
	}
	// 不做传送事件
	logic.PushOperate(updateData, 100)
}
